package jaux.message.codec;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

import jaux.message.codec.annotation.ByteMessageField;
import jaux.message.codec.utils.MessageClassUtils;

/**
 * 字节组成的消息的解码器.
 */
public class ByteMessageDecoder implements MessageDecoder {

	private static final Logger logger = LoggerFactory.getLogger(ByteMessageDecoder.class);

	private static final ExpressionParser parser = new SpelExpressionParser();
	/*
	 * (non-Javadoc)
	 * 
	 * @see jaux.message.codec.message.MessageDecoder#decode(java.lang.String,
	 * java.lang.Class)
	 */
	@Override
	public <T> T decode(String message, Class<T> clz) {
		if (message == null || message.equals("")) {
			return null;
		}
		message = message.toUpperCase();
		int[] dataBs = new int[message.length() / 2];
		/*
		 *  将原始数据转换为字节数组，作为解析的基础
		 */
		for (int i = 0; i < message.length(); i += 2) {
			dataBs[i / 2] = (byte) (Integer.parseInt(message.substring(i, i + 2), 16) & 0xff);
		}

		ByteMessage sa = new ByteMessage();
		sa.setBytes(dataBs);
		try {
			/*
			 * 查询目标类所有需要进行转换的字段
			 */
			T inst = clz.newInstance();

			List<Field> fields = MessageClassUtils.getMessageField(clz);
			/*
			 * 解析字节数据到需要赋值的字段上
			 */
			for (Field fi : fields) {
				setPropertyValue(sa, inst, fi);
			}
			return inst;
		} catch (InstantiationException | IllegalAccessException e) {
			logger.error("decode message bytes failed", e);
		}
		return null;
	}

	
	private void setPropertyValue(ByteMessage sa, Object inst, Field fi) {
		final ByteMessageField annotation = fi.getAnnotation(ByteMessageField.class);
		String bmfExp = annotation.value();
		if(StringUtils.isBlank(bmfExp))
			bmfExp = annotation.decoder();
		String getVarPrefix = "getVar\\(";
		String[] vpa = bmfExp.split(getVarPrefix);
		List<String> neededVars = new ArrayList<>();
		if(vpa.length>1) {
			for(String vpi: Arrays.copyOfRange(vpa, 1, vpa.length)) {
				neededVars.add(vpi.substring(0+1, vpi.indexOf(")")-1));
			}
		}
		for(String neededVar : neededVars) {
			if(sa.getFields().containsKey(neededVar))
				continue;
			setPropertyValue(sa, inst, FieldUtils.getField(inst.getClass(), neededVar) );
			
		}
		Object mm = null;
		try{
			mm = parser.parseExpression(bmfExp).getValue(sa);
		}catch (Exception e) {
			logger.warn("解析表达式失败："+bmfExp, e);
		}
		if(mm == null) {
			return;
		}
		sa.setVar(fi.getName(), mm);
		try {
			BeanUtils.setProperty(inst, fi.getName(), mm);
		} catch ( Exception e) {
			e.printStackTrace();
		}
	}

}
